﻿using Abp.Dependency;
using Magicodes.WeChat.SDK;
using Magicodes.WeChat.SDK.Builder;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Abp.Application.Services.Dto;
using Castle.Core.Logging;
using Abp.Runtime.Session;
using Magicodes.WeChat.Configuration;
using Abp.Configuration;
using Abp.Runtime.Caching;
using Newtonsoft.Json;
using Magicodes.WeChat.WeChatApiSetting.Dto;
using Microsoft.AspNetCore.Http;
using Abp.Json;
using Magicodes.WeChat.SDK.Apis.Token;
using Abp.Extensions;

namespace Magicodes.WeChat.Application.Startup
{
    /// <summary>
    /// 微信SDK配置
    /// </summary>
    public static class WeChatSDKConfigHelper
    {
        /// <summary>
        /// 配置WeChat SDK
        /// </summary>
        /// <param name="logger"></param>
        /// <param name="cacheManager"></param>
        public static void Config(ILogger logger, ICacheManager cacheManager)
        {
            #region 公众号SDK配置

            WeChatSDKBuilder.Create()
                //设置日志记录
                .WithLoggerAction((tag, message) => { logger.DebugFormat("Tag:{0}\tMessage:{1}", tag, message); })
                //注册Key。不再需要各个控制注册
                //通过租户Id的获取
                .Register(WeChatFrameworkFuncTypes.GetKey, model =>
                {
                    using (IocManager.Instance.CreateScope())
                    {
                        int? key = null;
                        var session = IocManager.Instance.Resolve<IAbpSession>();
                        if (session.ImpersonatorTenantId == null && session.TenantId == null)
                        {
                            //从请求参数中获取key
                            var httpContextAccessor = IocManager.Instance.Resolve<IHttpContextAccessor>();
                            if (httpContextAccessor != null)
                            {
                                var context = httpContextAccessor.HttpContext;
                                if (context != null && !string.IsNullOrWhiteSpace(context.Request.Query["TKey"]))
                                {
                                    key = Convert.ToInt32(context.Request.Query["TKey"]);
                                }
                            }
                        }
                        else
                        {
                            key = session.ImpersonatorTenantId ?? session.TenantId ?? null;
                        }
                        //TODO：修改通过配置文件配置
                        //如果key不存在，则使用1
                        key = key ?? 1;
                        logger.Debug("WeChatFrameworkFuncTypes.GetKey：" + key);
                        return key;
                    }
                })
                //通过缓存获取AccessToken
                .Register(WeChatFrameworkFuncTypes.APIFunc_GetAccessToken, model =>
                {
                    logger.Debug("通过缓存服务获取AccessToken");
                    #region 通过缓存服务获取AccessToken
                    var arg = model as WeChatApiCallbackFuncArgInfo;
                    var config = arg.Data as WeChatApiSettingEditDto;
                    var key = arg.Api.GetKey();
                    config = GetLastAccessToken(logger, cacheManager, config, key);
                    var tokenModel = new TokenApiResult()
                    {
                        AccessToken = config.AccessToken,
                        ExpiresTime = config.AccessTokenExpiresTime.Value
                    };
                    logger.Debug("通过缓存服务获取AccessToken：" + tokenModel.ToJsonString());
                    return tokenModel;
                    #endregion
                })
                //注册获取配置函数：根据Key获取微信配置（加载一次后续将缓存）
                .Register(WeChatFrameworkFuncTypes.Config_GetWeChatConfigByKey,
                    model =>
                    {
                        var arg = model as WeChatApiCallbackFuncArgInfo;
                        var key = (Convert.ToInt32(arg.Data));
                        logger.Debug("通过缓存服务获取微信配置：" + key);
                        var settingValue = cacheManager.GetCache("WeChatSetting").AsTyped<string, string>().Get(key.ToString(), () => GetWeChatSettingValue(key.ToString(), cacheManager, logger));
                        return GetLastAccessToken(logger, cacheManager, JsonConvert.DeserializeObject<WeChatApiSettingEditDto>(settingValue), key);
                    })
                .Register(WeChatFrameworkFuncTypes.Config_GetWeChatPayConfigByKey, model =>
                {
                    var arg = model as WeChatPayCallbackFuncArgInfo;
                    if (arg == null) return null;
                    var key = arg.Data;
                    var tenantId = (int?)key;
                    using (var _settingManager = IocManager.Instance.ResolveAsDisposable<ISettingManager>())
                    {
                        var settingValue = tenantId.HasValue
                        ? _settingManager.Object.GetSettingValueForTenant(WeChatSettings.TenantManagement.WeChatPayApiSettings,
                            tenantId.Value)
                        : _settingManager.Object.GetSettingValueForApplication(WeChatSettings.TenantManagement
                            .WeChatPayApiSettings);

                        return JsonConvert.DeserializeObject<WeChatPayApiSettingEditDto>(settingValue);
                    }
                })
                .Build();

            #endregion
        }

        /// <summary>
        /// 获取最新的AccessToken
        /// </summary>
        /// <param name="logger"></param>
        /// <param name="cacheManager"></param>
        /// <param name="config"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        private static WeChatApiSettingEditDto GetLastAccessToken(ILogger logger, ICacheManager cacheManager, WeChatApiSettingEditDto config, object key)
        {
            if (config.AccessToken.IsNullOrEmpty() || config.AccessTokenExpiresTime.Value < DateTime.Now.AddMinutes(1))
            {
                logger.Debug("Token过期或不存在，根据配置获取Token。OldInfo\tAccessToken:" + config.AccessToken + "\tAccessTokenExpiresTime:" + config.AccessTokenExpiresTime);
                var api = new TokenApi();
                api.SetKey(key);
                var accessTokenResult = api.GetByCustomConfig(config);
                config.AccessToken = accessTokenResult.AccessToken;
                config.AccessTokenExpiresTime = accessTokenResult.ExpiresTime;
                var value = config.ToJsonString();
                logger.DebugFormat("已重新获取AccessToken和配置：{0}", config.ToJsonString());
                cacheManager.GetCache("WeChatSetting").Set(key.ToString(), value);
            }
            return config;
        }

        /// <summary>
        /// 获取微信配置
        /// </summary>
        /// <param name="key"></param>
        /// <param name="cacheManager"></param>
        /// <param name="logger"></param>
        /// <returns></returns>
        private static string GetWeChatSettingValue(string key, ICacheManager cacheManager, ILogger logger)
        {

            using (var settingManager = IocManager.Instance.ResolveAsDisposable<ISettingManager>())
            {
                string settingValue = null;
                if (key == null)
                {
                    settingValue = settingManager.Object.GetSettingValueForApplication(WeChatSettings.TenantManagement
                        .WeChatApiSettings);
                }
                else
                {
                    settingValue = settingManager.Object.GetSettingValueForTenant(
                        WeChatSettings.TenantManagement.WeChatApiSettings,
                        Convert.ToInt32(key));
                }

                logger.DebugFormat("已从配置管理器中获取配置：{0}", settingValue);
                var config = GetLastAccessToken(logger, cacheManager, JsonConvert.DeserializeObject<WeChatApiSettingEditDto>(settingValue), key);
                return config.ToJsonString();
            }
        }
    }
}
